import { Browser, Page, CookieParam } from 'puppeteer';
import puppeteer from 'puppeteer-extra';
import StealthPlugin from 'puppeteer-extra-plugin-stealth';
import { logger } from '../utils/Logger';
import { Cluster } from 'puppeteer-cluster';
import fs from 'fs/promises';
import { City } from '../common/city';

puppeteer.use(StealthPlugin());

interface ISite {
  scrapeCities(): Promise<any>;
  scrape(): Promise<any>;
}

interface MonitorOptions {
  cookieFilePath?: string; // 传入文件路径，而不是直接的 cookies
  referer?: string;
}

export default class Site implements ISite {
  #url: string;
  cluster: Cluster | null;
  browser: Browser | null;
  constructor(url: string) {
    // private member variable
    this.#url = url;
    this.cluster = null;
    this.browser = null;
  }
  getCluster = async (): Promise<Cluster<any, any>> => {
    if (!this.cluster) {
      logger.info('init cluster handler!');
      this.cluster = await Cluster.launch({
        concurrency: Cluster.CONCURRENCY_CONTEXT,
        maxConcurrency: 1,
        puppeteerOptions: {
          // headless: true,
          headless: false,
          defaultViewport: { innerWidth: 800, innerHeight: 600 },
        },
        puppeteer: puppeteer,
      });
    }
    return this.cluster;
  };
  getLink() {
    return this.#url;
  }

  public async scrape(): Promise<any> {
    logger.error('Not implement!');
    return Promise.reject(new Error('Not implement!'));
  }
  public async scrapeCities(): Promise<any> {
    logger.error('Please implement it in subclass.');
    return Promise.reject(new Error('not implement'));
  }
  launchBrowser = async (): Promise<Browser> => {
    logger.debug('launch browser...');
    return puppeteer.launch({
      headless: false,
      args: [
        '--no-sandbox',
        '--disable-setuid-sandbox',
        '--disable-infobars',
        '--window-size=1366,768', // 设置窗口大小
        '--start-maximized', // 最大化窗口
      ],
    });
  };
  createSession = async (): Promise<string> => {
    logger.info('create steel session...');
    const createSession = {
      sessionContext: {
        ANY_ADDITIONAL_PROPERTY: 'anything',
      },
      extensions: [null],
      dimensions: {
        width: 1,
        height: 1,
      },
    };
    const url = `${process.env.STEEL_BASE_URL}/v1/sessions`;
    logger.info(`Create session with url:${url}`);
    const resp = await fetch(url, {
      method: 'POST',
      body: JSON.stringify(createSession),
      headers: { 'Content-Type': 'application/json' },
    });
    if (resp && resp.ok) {
      const content = await resp.json();
      return new Promise((resolve, reject) => {
        try {
          resolve(content.id);
        } catch (error) {
          logger.info(error);
          reject(new Error('Create session failed!'));
        }
      });
    }
    return Promise.reject(new Error('Create session failed'));
  };
  releaseSession = async (id: string): Promise<boolean> => {
    logger.info(`Release session:${id}`);
    return Promise.resolve(true);
  };
  newPage = async (id: string): Promise<Page> => {
    const browser = await puppeteer.connect({
      browserWSEndpoint: `${process.env.WS_URL}?apiKey=${process.env.STEEL_API_KEY}&sessionId=${id}`,
    });
    return browser.newPage();
  };

  async monitorHumanOpenTab(
    page: Page,
    options: MonitorOptions = {},
  ): Promise<Page> {
    const { cookieFilePath, referer = 'https://www.taobao.com/' } = options;

    try {
      // 如果提供了 cookie 文件路径，读取并设置 cookies
      if (cookieFilePath) {
        const cookies = await this.getCookieFromFile(cookieFilePath);
        if (cookies && cookies.length > 0) {
          // 使用循环设置 cookies，避免 deprecated 警告
          for (const cookie of cookies) {
            await page.setCookie(cookie);
          }
        }
      }

      await page.setUserAgent(
        'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36',
      );

      await page.setViewport({
        width: 1366,
        height: 768,
        deviceScaleFactor: 1,
      });

      await page.evaluateOnNewDocument(() => {
        Object.defineProperty(navigator, 'webdriver', { get: () => false });
        Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3] });
        Object.defineProperty(window, 'screen', {
          get: () => ({
            width: 1366,
            height: 768,
            availWidth: 1366,
            availHeight: 768,
          }),
        });
      });

      await page.setExtraHTTPHeaders({
        'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
        Accept:
          'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
        Referer: referer,
        Connection: 'keep-alive',
      });

      await page.mouse.move(Math.random() * 800, Math.random() * 600, {
        steps: 10,
      });
      return page;
    } catch (error) {
      console.error('模拟人类打开标签失败:', error);
      throw error;
    }
  }

  // 独立的 getCookieFromFile 函数
  async getCookieFromFile(
    filepath: string,
  ): Promise<CookieParam[] | undefined> {
    try {
      if (!filepath) {
        throw Error('传入的cookie路径异常');
      }
      const data = await fs.readFile(filepath, 'utf-8');
      const cookies: CookieParam[] = JSON.parse(data);
      return cookies;
    } catch (err) {
      console.error('读取或解析 cookies 文件失败:', err);
      return undefined;
    }
  }

  // 关闭页面
  async closePage(page: Page): Promise<void> {
    logger.debug('关闭新页面');
    try {
      await page.close();
      logger.debug('页面已关闭');
    } catch (err) {
      logger.error(`关闭页面失败: ${err}`);
    }
  }
}
